Skip to content

Fix ARCHIVED → TODO transition on Cmd/Ctrl+Enter#17

Open
salmonumbrella wants to merge 3 commits intoRoamJS:mainfrom
salmonumbrella:fix/archived-to-todo
Open

Fix ARCHIVED → TODO transition on Cmd/Ctrl+Enter#17
salmonumbrella wants to merge 3 commits intoRoamJS:mainfrom
salmonumbrella:fix/archived-to-todo

Conversation

@salmonumbrella
Copy link
Copy Markdown

@salmonumbrella salmonumbrella commented Feb 28, 2026

Summary

  • When pressing Cmd/Ctrl+Enter on an ARCHIVED block, Roam prepends TODO resulting in TODO+ARCHIVED. This normalizes that into just TODO.
  • Reads block text from Roam's data layer (getTextByBlockUid) instead of the textarea DOM value, which can lag behind after API updates.
  • Adds a new normalizeTodoArchivedPrefix utility that collapses {{[[TODO]]}} {{[[ARCHIVED]]}} into {{[[TODO]]}}.
PR17.for.Droidian.mp4

Test plan

  • Place cursor on an ARCHIVED block → press Cmd/Ctrl+Enter → block becomes TODO (not TODO+ARCHIVED)
  • Place cursor on a TODO block → press Cmd/Ctrl+Enter → block becomes DONE (unchanged behavior)
  • Place cursor on a DONE block → press Cmd/Ctrl+Enter → block becomes TODO (unchanged behavior)

Closes #4

Summary by CodeRabbit

  • Bug Fixes

    • Improved handling of ARCHIVED TODO items when using keyboard shortcuts to toggle status.
    • Fixed inconsistent behavior when using keyboard shortcuts to change TODO state.
  • New Features

    • Enhanced keyboard shortcut processing to properly normalize and handle ARCHIVED items consistently.

Open with Devin

When pressing Cmd/Ctrl+Enter on an ARCHIVED block, Roam prepends
TODO to get TODO+ARCHIVED. This collapses that into just TODO.

Also reads block text from Roam's data layer instead of the textarea
DOM value, which can lag behind after API updates.

Closes RoamJS#4
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Feb 28, 2026

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 2a57b903-24a6-4061-8d08-8c3bdccbaa95

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

This PR introduces a new utility module for normalizing TODO blocks with an ARCHIVED prefix pattern and integrates it into the main handler. The keyboard shortcut logic is refactored to read block text from Roam's data layer rather than directly from the textarea value, enabling consistent detection and handling of ARCHIVED, DONE, and TODO prefixed blocks during block state transitions.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main fix: resolving ARCHIVED → TODO transition on keyboard shortcut, which is the primary focus of the changeset.
Linked Issues check ✅ Passed The pull request addresses the core requirement from issue #4 by implementing ARCHIVED → TODO normalization with proper handling during keyboard shortcuts.
Out of Scope Changes check ✅ Passed All changes are directly aligned with fixing ARCHIVED → TODO transitions; the addition of normalizeTodoArchivedPrefix utility and the Cmd/Ctrl+Enter handler logic are both essential to the stated objective.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@salmonumbrella
Copy link
Copy Markdown
Author

@mdroidian broke these up for you! please take a look ❤️

@salmonumbrella
Copy link
Copy Markdown
Author

@mdroidian broke these up for you! please take a look ❤️ (again, again)

@mdroidian
Copy link
Copy Markdown
Contributor

@coderabbitai full review

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 11, 2026

✅ Actions performed

Full review triggered.

coderabbitai[bot]

This comment was marked as resolved.

Copy link
Copy Markdown

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 5 additional findings.

Open in Devin Review

Comment on lines +132 to +134
// Roam's Cmd/Ctrl+Enter prepends TODO for non-checkbox blocks.
// If the block starts with ARCHIVED, collapse TODO+ARCHIVED into TODO.
value = normalizeTodoArchivedPrefix(value);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚩 normalizeTodoArchivedPrefix is unlikely to match in current onTodo call sites

The normalization regex /^(\{\{\[\[TODO\]\]\}\})\s*\{\{\[\[ARCHIVED\]\]\}\}/ requires text to start with {{[[TODO]]}} followed by {{[[ARCHIVED]]}}. Current onTodo callers pass text starting with {{[[DONE]]}} (keydown handler line 378), post-toggle text from checkbox click (line 318), or textarea value from click listener (line 345). None of these would typically produce a {{[[TODO]]}}{{[[ARCHIVED]]}} prefix. The normalization acts as a defensive guard but may never match in practice. Consider whether there's an actual code path that produces this pattern, or if the normalization should be placed elsewhere.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +363 to +376
if (blockText.startsWith("{{[[ARCHIVED]]}}")) {
e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();
const withoutArchived = blockText.replace(
/^\{\{\[\[ARCHIVED\]\]\}}\s*/,
"",
);
const normalized = withoutArchived
? `{{[[TODO]]}} ${withoutArchived}`
: "{{[[TODO]]}}";
if (normalized !== blockText) {
updateBlock({ uid: blockUid, text: normalized });
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚩 ARCHIVED→TODO transition does not trigger onTodo settings

When a block starts with {{[[ARCHIVED]]}}, the keydown handler converts it to {{[[TODO]]}} via updateBlock but does NOT call onTodo(). This means user-configured "On Todo" append text, tag replacements, and other onTodo triggers are skipped for ARCHIVED→TODO transitions. This appears intentional (un-archiving is distinct from creating a new TODO), but it's a behavioral choice worth confirming with the author if "On Todo" settings should also fire when restoring from ARCHIVED state.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

src/index.ts Outdated
Comment on lines 377 to 381
} else if (blockText.startsWith("{{[[DONE]]}}")) {
onTodo(blockUid, blockText);
} else if (blockText.startsWith("{{[[TODO]]}}")) {
onDone(blockUid, blockText);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚩 Race condition between onTodo/onDone updateBlock and Roam's Ctrl+Enter toggle

For DONE and TODO cases (lines 377-381), neither e.preventDefault() nor e.stopImmediatePropagation() is called, so Roam will also process Ctrl+Enter and toggle the block prefix. Meanwhile onTodo/onDone may call updateBlock with text that still has the old prefix (e.g., {{[[DONE]]}} modified text). Depending on timing, Roam's toggle and the extension's updateBlock could conflict. This is a pre-existing architectural issue (the old code had the same pattern), not introduced by this PR, but it's worth noting that the callback swap makes modifications more semantically correct — and thus more likely to actually change the text — which could make the race more visible in practice.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@mdroidian mdroidian self-requested a review March 15, 2026 18:53
Copy link
Copy Markdown
Contributor

@mdroidian mdroidian left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the contribution! Here's a video review:

https://www.loom.com/share/8640bd817d8c4d00bf1a0e0bdddf9bf7

Points

  • Observed a regression in ToDoTrigger behavior compared to the previous version.
  • Open Devin bug report comments.
  • To move forward with a change like this, a full set of unit tests covering each feature/function of this repo will likely be required (ETA unknown), or a Loom video demonstrating the compiled PR running through each feature/function to confirm that no regressions have been introduced.

The single-block handler was reading getTextByBlockUid (pre-toggle
data layer) and using inverted routing. This caused a race with
Roam's own toggle — onDone/onTodo received text with the wrong
prefix, leading to duplicated append text instead of clean toggling.

Reverting to textArea.value (which Roam updates synchronously on
Ctrl+Enter) with standard routing (DONE→onDone, TODO→onTodo) fixes
the regression. The ARCHIVED handler still uses getTextByBlockUid
since textarea lags for that specific case.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@salmonumbrella
Copy link
Copy Markdown
Author

@mdroidian thank you for the thorough video review! Really appreciate you catching that regression.

I pushed a fix in 6035965 — the root cause was that the single-block Ctrl+Enter handler was reading getTextByBlockUid (Roam's data layer, which hasn't toggled yet at that point) instead of textArea.value (which Roam updates synchronously). This caused a race where onDone/onTodo received text with the wrong prefix, leading to the duplicated append text you saw.

The fix reverts the TODO/DONE cases to read textArea.value with standard routing (DONE→onDone, TODO→onTodo), while keeping the ARCHIVED handler on getTextByBlockUid since the textarea genuinely lags for that specific case.

Happy to record a Loom walkthrough if you'd like visual confirmation before merging.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Handle ARCHIVED => TODO

2 participants